﻿using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.IO;
using System.Linq;
using System.Windows;
using System.Windows.Input;

namespace xCarLinkMP3Organizer
{
    public class DiscViewModel : BaseViewModel, IDisposable, IComparable, IComparable<DiscViewModel>
    {
        private readonly UsbDrive _drive;
        private readonly ViewModel _vm;
        private string _header;
        private bool _isOwnWinamp;
        private int _number;
        private FSWWrapper _fsw;

        private ICommand _getFromWinampCmd;
        private ICommand _openInWinampCmd;
        private ICommand _removeCmd;

        public DiscViewModel(ViewModel vm, UsbDrive drive, int number)
        {
            _vm = vm;
            _drive = drive;
            _number = number;
            _header = GetDirName();

            if (!Directory.Exists(Path))
                Directory.CreateDirectory(Path);

            CreateWatcher();
        }

        private void CreateWatcher()
        {
            _fsw = new FSWWrapper(Path)
                       {
                           EnableRaisingEvents = true,
                           IncludeSubdirectories = true,
                       };
            _fsw.Deleted += OnMyDirDeleted;
            _fsw.Created += OnMyDirCreated;
            _fsw.Renamed += OnMyDirRenamed;
        }

        public ICommand OpenInWinampCmd
        {
            get { return _openInWinampCmd ?? (_openInWinampCmd = new LambdaViewCommmand(OpenInWinamp)); }
        }

        public ICommand GetFromWinampCmd
        {
            get { return _getFromWinampCmd ?? (_getFromWinampCmd = new LambdaViewCommmand(GetFromWinamp)); }
        }

        public ICommand RemoveCmd
        {
            get { return _removeCmd ?? (_removeCmd = new LambdaViewCommmand(RemoveMe)); }
        }

        private void RemoveMe(object obj)
        {
            if (Directory.Exists(Path))
            {
                if (MessageBox.Show("Remove " + Path + "?", "Disk", MessageBoxButton.OKCancel) ==
                    MessageBoxResult.OK)
                    new LongOperation(1, RemoveMe)
                        .Do();
            }
        }

        private IEnumerable<string> RemoveMe()
        {
            yield return "Deleting " + Path;
            Directory.Delete(Path, true);
        }

        public string Path
        {
            get { return _drive.Name + "\\" + GetDirName(); }
        }

        public int Number
        {
            get { return _number; }
            set
            {
                if (_number == value)
                    return;

                _number = value;
                PropChanged("Number");
                PropChanged("Header");
            }
        }

        public bool IsOwnWinamp
        {
            get { return _isOwnWinamp; }
            set
            {
                _isOwnWinamp = value;
                
                if (_isOwnWinamp)
                {
                    var startEmptyWinamp = new StartEmptyWinamp();
                    startEmptyWinamp.Execute(this);
                }
                
                PropChanged("IsOwnWinamp");
            }
        }

        public IEnumerable<string> GetFiles()
        {
            return Directory.EnumerateFiles(Path);
        }

        public string Header
        {
            get { return _header; }
            set
            {
                if (_header == value)
                    return;
                _header = value;
                PropChanged("Header");
            }
        }

        #region IDisposable Members

        public void Dispose()
        {
            if (_fsw != null)
            {
                _fsw.Deleted -= OnMyDirDeleted;
                _fsw.Created -= OnMyDirCreated;
                _fsw.Renamed -= OnMyDirRenamed;
                _fsw.Dispose();
                _fsw = null;
            }
        }

        #endregion

        private void GetFromWinamp(object obj)
        {
            var cmd = new GetWinampPlayList();
            cmd.Execute(this);

            if (cmd.Files == null)
                return;

            var winampFiles = cmd.Files.ToArray();
            var currFiles = GetFiles().ToArray();
            var filesToDelete = currFiles.Except(winampFiles).ToArray();
            var filesToAdd = winampFiles.Except(currFiles).ToArray();

            new LongOperation(
                filesToDelete.Length + filesToAdd.Length + 1,
                () => SyncPlaylist(Path, winampFiles, filesToDelete, filesToAdd))
                .Do();
        }

        private IEnumerable<string> SyncPlaylist(string path, string[] winampFiles, string[] filesToDelete, string[] filesToAdd)
        {
            int i = -filesToDelete.Length;
            foreach (string fileToDelete in filesToDelete)
            {
                yield return "Deleting " + System.IO.Path.GetFileName(fileToDelete);

                if (File.Exists(fileToDelete))
                    File.Delete(fileToDelete);
            }

            foreach (string fileToAdd in filesToAdd)
            {
                yield return "Copying " + System.IO.Path.GetFileName(fileToAdd);

                if (File.Exists(fileToAdd))
                {
                    string destFileName = System.IO.Path.Combine(
                        Path,
                        System.IO.Path.GetFileName(fileToAdd));

                    File.Copy(fileToAdd, destFileName, true);
                }
            }

            yield return "Sorting...";

            var tempPath = Path + "." + Guid.NewGuid();
            Directory.Move(Path, tempPath);
            Directory.CreateDirectory(Path);

            foreach (var file in winampFiles)
            {
                var fileName = System.IO.Path.GetFileName(file);
                var sourceFileName = System.IO.Path.Combine(tempPath, fileName);
                var destFileName = System.IO.Path.Combine(Path, fileName);
                File.Move(sourceFileName, destFileName);
            }

            Directory.Delete(tempPath);
        }

        private void OpenInWinamp(object parameter)
        {
            _vm.WinampActive = this;
        }

        private void OnMyDirRenamed(object sender, RenamedEventArgs e)
        {
            _vm.RequestUpdateDiskInfo();
        }

        private void OnMyDirCreated(object sender, FileSystemEventArgs e)
        {
            _vm.RequestUpdateDiskInfo();
        }

        private void OnMyDirDeleted(object sender, FileSystemEventArgs e)
        {
            _vm.RequestUpdateDiskInfo();
        }

        private string GetDirName()
        {
            return "CD" + _number.ToString("00");
        }

        public void CheckWinampActive()
        {
            if (!WinampLib.IsOpened())
                _vm.WinampActive = null;
        }


        public int CompareTo(object obj)
        {
            return CompareTo((DiscViewModel) obj);
        }

        public int CompareTo(DiscViewModel other)
        {
            return String.Compare(Path, other.Path);
        }
    }
}